import { RegisterComponent } from "@feng3d/ecs";
import { watcher } from "@feng3d/watcher";
import { Color, Scene } from "../../thirdparty/three/imports";
import { Component3D } from "../core/Component3D";
import { Texture3D } from "../textures/Texture3D";
import { FogBase3D } from "./FogBase3D";

declare module "@feng3d/ecs"
{
    interface ComponentMap { Scene3D: Scene3D; }
}

/**
 * 3D场景，包装`three`中`Scene`
 */
@RegisterComponent({ name: 'Scene3D' })
export class Scene3D extends Component3D
{
    /**
     * @private
     */
    _scene: Scene;

    get background()
    {
        if (this._scene)
        {
            const background = this._scene.background;
            if (background instanceof Color)
            {
                this._background = background;
            }
            else
            {
                this._background = Texture3D.get(background);
            }
        }

        return this._background;
    }
    set background(v)
    {
        this._background = v;
        if (this._scene)
        {
            const background = this._background;
            if (background instanceof Color)
            {
                this._scene.background = background;
            }
            else
            {
                this._scene.background = background?._texture;
            }
        }
    }
    private _background: Color | Texture3D;

    get environment()
    {
        if (this._scene)
        {
            this._environment = Texture3D.get(this._scene.environment);
        }

        return this._environment;
    }
    set environment(v)
    {
        this._environment = v;
        if (this._scene)
        {
            this._scene.environment = v._texture;
        }
    }
    private _environment: Texture3D;

    get fog()
    {
        if (this._scene)
        {
            this._fog = FogBase3D.get(this._scene.fog);
        }

        return this._fog;
    }
    set fog(v)
    {
        this._fog = v;
        this._scene.fog = this._fog._fog;
    }
    private _fog: FogBase3D;

    get overrideMaterial()
    {
        return this._scene.overrideMaterial;
    }
    set overrideMaterial(v)
    {
        this._scene.overrideMaterial = v;
    }

    init()
    {
        super.init();

        this._scene ||= new Scene();
        this._scene.add(this._entity._group);

        watcher.watchs(this as Scene3D, ["environment"], this._onWatched, this);
    }

    destroy(): void
    {
        watcher.unwatchs(this as Scene3D, ["environment"], this._onWatched, this);

        this._scene.remove(this._entity._group);
        this._scene = null;

        super.destroy();
    }

    private _onWatched(newValue: any, oldValue: any, object: Scene3D, property: keyof Scene3D)
    {
        switch (property)
        {
            case "environment":
                this._scene.environment = this.environment?._texture;
                break;
        }
    }
}
